2023/12/235036字符

二叉平衡搜索树

  • 每个节点的左子树与右子树的高度不超过 1
function Node (value) {
    this.value = value;
    this.left = null;
    this.right = null;
}

const a = new Node('a');
const b = new Node('b');
const c = new Node('c');
const d = new Node('d');
const e = new Node('e');
const f = new Node('f');
const g = new Node('g');

a.left = b;
b.left = d;
b.right = e;
c.left = f;
c.right = g;

是否为平衡树

// 获取二叉树的深度
function getDeep (root) {
    if (root == null || root == undefined) return 0;
    let leftDeep = getDeep(root.left);
    let rightDeep = getDeep(root.right);
    return Math.max(leftDeep, rightDeep) + 1;
}

// 二叉树是否平衡
function isBalance (root) {
    if (root == null) return true;
    let leftDeep = getDeep(root.left);
    let rightDeep = getDeep(root.right);
    if (Math.abs(leftDeep - rightDeep) > 1) {  // 不平衡
        return false;
    } else {
        return isBalance(root.left) && isBalance(root.right);
    }
}

console.log(getDeep(a));  //--> 3
console.log(isBalance(a));  //--> false

单璇

  • 左单璇:右子树比左子树深度深,需进行左单璇
  • 右单璇:左子树比右子树深度深,需进行右单璇
  • 怎样做单璇:
    • 不平衡的节点为旋转节点
// 左旋
function leftRotate (root) {
    let newRoot = root.right;  // 新的根
    let changeTree = root.right.left;
    root.right = changeTree;
    newRoot.left = root;
    return newRoot;
}
// 右旋
function rightRotate (root) {
    let newRoot = root.left;
    let changeTree = root.left.right;
    root.left = changeTree;
    root.right = root;
    return newRoot;
}

function change (root) {
    if (isBalance(root)) return root;
    if (root.left != null) root.left = change(root.left);
    if (root.right != null) root.right = change(root.right);
    let leftDeep = getDeep(root.left);
    let rightDeep = getDeep(root.right);
    if (Math.abs(leftDeep - rightDeep) < 2) {  // 平衡
        return root;
    } else if (leftDeep > rightDeep) {  // 左子树深,进行右旋
        return rightRotate(root);
    } else {  // 右子树深,进行左旋
        return leftRotate(root);
    }
    return root;
}

const newRoot = change(a);  // 单璇后看谁是根节点,再进行 isBalance 判断
console.log(isBalance(newRoot));  //--> true

双璇

为解决左子树或右子树单一边有子节点的问题

  • 左右双璇与右左双璇
    • a.left = b, b.left = c, c.left = d, d.left = e, e.left = f; ```js function change (root) { if (isBalance(root)) return root; if (root.left != null) root.left = change(root.left); if (root.right != null) root.right = change(root.right); let leftDeep = getDeep(root.left); let rightDeep = getDeep(root.right); if (Math.abs(leftDeep - rightDeep) < 2) { // 平衡 return root; } else if (leftDeep > rightDeep) { // 左子树深,进行右旋 let changeTreeDeep = getDeep(root.left.right); let noChangeTreeDeep = getDeep(root.left.left); if (changeTreeDeep > noChangeTreeDeep) { root.left = leftRotate(root.left); } return rightRotate(root); } else { // 右子树深,进行左旋 let changeTreeDeep = getDeep(root.right.left); let noChangeTreeDeep = getDeep(root.right.right); if (changeTreeDeep > noChangeTreeDeep) { root.right = rightRotate(root.right); } return leftRotate(root); } return root; }

const newRoot = change(a); console.log(isBalance(newRoot)); //--> true


- 左左双璇与右右双璇

```js
function change (root) {
    if (isBalance(root)) return root;
    if (root.left != null) root.left = change(root.left);
    if (root.right != null) root.right = change(root.right);
    let leftDeep = getDeep(root.left);
    let rightDeep = getDeep(root.right);
    if (Math.abs(leftDeep - rightDeep) < 2) {  // 平衡
        return root;
    } else if (leftDeep > rightDeep) {  // 左子树深,进行右旋
        let changeTreeDeep = getDeep(root.left.right);
        let noChangeTreeDeep = getDeep(root.left.left);
        if (changeTreeDeep > noChangeTreeDeep) {
            root.left = leftRotate(root.left);
        }
        let newRoot = rightRotate(root);
        newRoot.right = change(newRoot);
        newRoot = change(newRoot);
        return newRoot;
    } else {  // 右子树深,进行左旋
        let changeTreeDeep = getDeep(root.right.left);
        let noChangeTreeDeep = getDeep(root.right.right);
        if (changeTreeDeep > noChangeTreeDeep) {
            root.right = rightRotate(root.right);
        }
        let newRoot = leftRotate(root);
        newRoot.left = change(newRoot);
        newRoot = change(newRoot);
        return newRoot;
    }
    return root;
}